<template>
    <div class='homebox'>
        <div class="back" @click="$router.go(-1)">
            <img src="../assets/img/back1.png" alt="">
            数据图谱
        </div>
        <div class="dia-search">
            <div v-if="searchType">
                <span>关键字：</span>
                <el-input
                    style="width:15vw;margin:0 0.6vw;"
                    placeholder="请输入关键字"
                    v-model="keywords"
                    clearable
                    size="mini">
                </el-input>
                <span>节点数量：</span>
                <el-select v-model="valueNum" placeholder="请选择" size="mini" style="width:6vw;margin:0 0.6vw;">
                    <el-option
                        v-for="item in options"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value">
                    </el-option>
                </el-select>
                <el-input
                    v-if="valueNum=='自定义'"
                    style="width:6vw;margin:0 0.6vw;"
                    placeholder="请输入"
                    v-model="limit"
                    clearable
                    size="mini">
                </el-input>
                <el-button type="primary" size="mini" @click="getDomainGraph">检索</el-button>
            </div>
            <div v-else style="position:relative;">
                <div class="tip">如：MATCH p=()-->() RETURN p LIMIT 25</div>
                <el-input
                    style="width:30vw;margin-right:0.6vw;"
                    placeholder="请输入Cypher语句"
                    v-model="cypher"
                    clearable
                    size="mini">
                </el-input>
                <el-button type="primary" size="mini" @click="getCypherResult">执行</el-button>
            </div>
            <el-button type="success" size="mini" style="margin-left:0.6vw;" @click="searchType=!searchType">{{searchType?'高级检索':'普通检索'}}</el-button>
        </div>
        <div class="graph-box">
            <div class="tab-box">
                <div @click="iconClick(1)" :class="active==1?'active':''">图谱</div>
                <div @click="iconClick(2)" :class="active==2?'active':''">JSON</div>
            </div>
            <div v-show="active==1" :class="full?'full-screen':'show-box'">
                <!-- 底部节点数据 -->
                <div class="data_box" v-html="vertexData"></div>
                <!-- 导出图片 -->
                <div @click="loadPng" class="loadPng" title="导出图片">
                    <i class="el-icon-picture-outline"></i>
                </div>
                <!-- 全屏按钮 -->
                <div @click="fullScreen" class="screenPng" :title="full?'退出全屏':'全屏'">
                    <i :class="full?'el-icon-aim':'el-icon-full-screen'"></i>
                </div>
                <!-- 节点右键菜单 -->
                <div class="custom-menu" style="width:80px">
                    <div><span @click="lockNode"><i class="el-icon-lock"></i> 锁定节点</span></div>
                    <div><span @click="deleteNode"><i class="el-icon-delete"></i> 删除节点</span></div>
                </div>
                <!-- 关系图 -->
                <div id="vis_box" style="height:100%"></div>
            </div>
            <div v-show="active==2" class="show-box">
                <!-- copyable  boxed -->
                <json-viewer :value="viewerData" :expand-depth=3 sort class="page_scroll"></json-viewer>
            </div>
        </div>
    </div>
</template>

<script>
const vis = require("vis-network/dist/vis-network.min.js");
require("vis-network/dist/dist/vis-network.min.css");
import {parseTime,errortip,successtip,warningtip} from '@/utils/util.js';
export default {
    name: '',
    data () {
        return {
            searchType: true,
            cypher: '',
            keywords: '',
            valueNum: 50,
            limit: '',
            options: [
                {label: 50,value: 50},
                {label: 100,value: 100},
                {label: 200,value: 200},
                {label: '自定义',value: '自定义'},
            ],
            active: 1,
            viewerData: {
                total: 25,
                limit: 10,
                skip: 0,
                links: {
                    previous: undefined,
                    next: function () {},
                },
            },
            graphNodes: [],
            graphEdges: [],
            currentNodeId: '',  //当期选中节点id
            vertexData: '',  //节点详细数据
            full: false,  //是否全屏
        }
    },
    components: {
        
    },
    created() {

    },
    mounted() {
        this.keywords = this.$route.query.keywords;
        this.getDomainGraph();
        this.$nextTick(() => {
            // 监听ESC退出全屏
            document.addEventListener('keyup', (e) => {
                if (e.keyCode == 27) {
                    this.full = false;
                }
            })
        })
    },
    methods: {
        // 点击切换数据展示形式
        iconClick(n) {
            this.active = n;
        },
        // 查询图节点和关系
        getDomainGraph() {
            let params = {
                nodename: this.keywords,
                pageSize: this.valueNum=='自定义'?this.limit||50:this.valueNum
            };
            this.$api.graph.getDomainGraph(params).then(res => {
                if(res.code==200) {
                    this.drawGraph(res.data.node, res.data.relationship);
                    this.viewerData = res.data;
                } else {
                    errortip(res.msg)
                }
            })
        },
        // 执行Cypher查询
        getCypherResult() {
            if(this.cypher === '') {
                warningtip('请输入Cypher语句');
                return false;
            }
            let params = {
                cypher: this.cypher
            };
            this.$api.graph.getCypherResult(params).then(res => {
                if(res.code==200) {
                    this.drawGraph(res.data.node, res.data.relationship);
                    this.viewerData = res.data;
                } else {
                    errortip(res.msg)
                }
            })
        },
         // 绘制graph关系图
        drawGraph(vertices, edges, styles) {
            this.graphNodes = [];
            this.graphEdges = [];
            this.currentNodeId = '';
            this.vertexData = '';
            this.graphNodes = new vis.DataSet();
            this.graphEdges = new vis.DataSet();
            // 添加点数据
            if (vertices !== null) {
                vertices.forEach(vertex => {
                    let title = this.titleHandleNode(vertex)
                    const container = document.createElement("div");
                    container.innerHTML = title;
                    this.graphNodes.add([{
                        id: vertex.uuid,
                        label: vertex.name,
                        // title: container,
                        group: vertex.name,
                        vertex: vertex,
                    }]);
                });
            }
            // 添加边数据
            if (edges !== null) {
                edges.forEach(edge => {
                    let title = this.titleHandleEdge(edge)
                    const container = document.createElement("div");
                    container.innerHTML = title;
                    this.graphEdges.add([
                        {
                            id: edge.uuid,
                            from: edge.sourceid,
                            to: edge.targetid,
                            // label: edge.label,
                            // title: container,
                            edge: edge,
                        }
                    ]);
                });
            }
            const container = document.getElementById('vis_box');
            const data = {
                nodes: this.graphNodes,
                edges: this.graphEdges,
            };
            // graph关系图配置
            const options = {
                autoResize: true,
                width: '100%',
                interaction: {
                    hover: true,
                    navigationButtons: true,
                    zoomView: true
                },
                nodes: {
                    font: {
                        color: "#fff",
                        face: "arial",
                        multi: false,
                        size: 12,
                    },
                    scaling: {
                        min: 10,
                        max: 30
                    },
                    shape: 'dot',
                    color: {
                        background: '#00ccff',
                        border: '#00ccff',
                        highlight: {background: '#fb6a02', border: '#fb6a02'},
                        hover: {background: '#ec3112', border: '#ec3112'}
                    },
                    borderWidth: 3,
                    shadow: {
                        enabled: true,
                        color: 'rgba(1, 187, 223, 1)',
                        size: 12,
                        x: 0,
                        y: 0,
                    },
                },
                edges: {
                    physics: true,
                    shadow: false,
                    smooth: {
                        type: 'dynamic'
                    },
                    font: {
                        color: "#fff",
                        face: "arial",
                        multi: false,
                        size: 11,
                    },
                    arrows: 'to',
                    color: {
                        color: "#39ADF1",
                        highlight: "#01BBDF",
                        hover: "#01BBDF",
                    },
                },
                physics: {
                    maxVelocity: 50,
                    solver: 'barnesHut',
                    timestep: 0.3,
                    stabilization: {iterations: 150}
                }
            };
            const network = new vis.Network(container, data, options);
            // // 鼠标滑过
            // network.on("hoverNode", (params) => this.hoverNode(params));
            // // 鼠标移开
            // network.on("blurNode", (params) => this.blurNode(params));
            // 双击事件
            network.on("doubleClick", (params) => this.doubleClick(params));
            // 单击事件
            network.on("click", (params) => this.leftClick(params));
            // 右击事件
            let _this = this;
            network.on("oncontext", function(params) {
                _this.hideCustomMenu()
                var nodeId = this.getNodeAt(params.pointer.DOM);
                if (nodeId){
					params.event.preventDefault();
				    $(".custom-menu").finish().toggle(100);
				    $(".custom-menu").css({
				        top: params.pointer.DOM.y + "px",
				        left: params.pointer.DOM.x + "px"
				    });
				    _this.currentNodeId = nodeId;
				}
            });
        },
        // // 鼠标滑过节点
        // hoverNode(params) {
        //     console.log(params)
        //     if (params.node) {
        //         var nodedata = this.graphNodes.get(params.node).vertex;
        //         this.vertexData = '';
        //         for(let k in nodedata) {
        //             this.vertexData +=  '<span class="data_label"> '+k+':&nbsp;</span>'+nodedata[k];
        //         }
        //     }
        // },
        // // 鼠标离开节点
        // blurNode(params) {
        //     this.vertexData = '';
        // },
        // 单击节点获取节点数据
        leftClick(params) {
            this.vertexData = '';
            if (params.nodes.length > 0) {
                var nodedata = this.graphNodes.get(params.nodes[0]).vertex;
                for(let k in nodedata) {
                    this.vertexData +=  '<span class="data_label"> '+k+':&nbsp;</span>'+nodedata[k];
                }
            }
            this.hideCustomMenu();
        },
        // 双击节点扩展关系图
        doubleClick(params) {
            params.event = "[original event]";
            if (params.nodes.length > 0) {
                let nodeId = params.nodes[0];
                let name = this.graphNodes.get(nodeId).label;
                let reqparams = {
                    nodename: name,
                }
                this.$api.graph.getDomainGraph(reqparams).then(res => {
                    if(res.code==200) {
                        this.addNode(res.data.node);
                        this.addEdge(res.data.relationship);
                    } else {
                        errortip(res.msg)
                    }
                })
            }
        },
        // 添加节点
        addNode(vertices) {
            try {
                if (vertices !== null) {
                    vertices.forEach(vertex => {
                        let title = this.titleHandleNode(vertex)
                        const container = document.createElement("div");
                        container.innerHTML = title;
                        if(!this.graphNodes.get(vertex.uuid)) {
                            this.graphNodes.add({
                                id: vertex.uuid,
                                label: vertex.name,
                                // title: container,
                                group: vertex.name,
                                vertex: vertex,
                            });
                            this.viewerData.node.push(vertex)
                        }
                        
                    });
                }
            } catch (err) {
                console.log(err);
            }
        },
        // 添加边
        addEdge(edges) {
            try {
                if (edges !== null) {
                    edges.forEach(edge => {
                        let title = this.titleHandleEdge(edge)
                        const container = document.createElement("div");
                        container.innerHTML = title;
                        if(!this.graphEdges.get(edge.uuid)) {
                            this.graphEdges.add([
                                {
                                    id: edge.uuid,
                                    from: edge.sourceid,
                                    to: edge.targetid,
                                    // label: edge.label,
                                    // title: container,
                                    edge: edge,
                                }
                            ]);
                            this.viewerData.relationship.push(edge)
                        }
                    });
                }
            } catch (err) {
                console.log(err);
            }
        },
        // 设置关系图节点tooltip  title
        titleHandleNode(data) {
            let title = '';
            for(let k in data) {
                title +=  '<div class="tooltips-label"> ' +
                    '<a class="round-gray">●</a>&nbsp;' +
                    k+' : ' + data[k] + '</div>'
            }
            return title;
        },
        // 设置关系图边tooltip  title
        titleHandleEdge(data) {
            // let title =
            //     '<div class="tooltips-label"> ' +
            //     '<a class="round-red">●</a>&nbsp;' +
            //     '标签 : ' + data.name + '</div>';
            // return title;
        },
        // 锁定节点
        lockNode() {
            let nodeData = this.graphNodes.get(this.currentNodeId);
            if(nodeData.fixed&&nodeData.fixed.x) {
                nodeData.fixed = {x: false, y: false}
            } else {
                nodeData.fixed = {x: true, y: true}
            }
            this.graphNodes.update({...nodeData});
            this.hideCustomMenu();
        },
        // 删除节点
        deleteNode() {
            this.graphNodes.remove({id: this.currentNodeId});
            this.hideCustomMenu();
        },
        // 隐藏右键菜单
        hideCustomMenu() {
            $(".custom-menu").hide();
        },
        // 导出图片
        loadPng() {
            $("#vis_box canvas").attr("id","c1");
            var oc=document.getElementById("c1");
            var createCanvas=document.createElement("canvas");
            createCanvas.width=$('#vis_box canvas').width();
            createCanvas.height=$('#vis_box canvas').height();
            var cvs=createCanvas.getContext("2d");
            function download(type) {
                //设置保存图片的类型
                var imgdata = oc.toDataURL(type);
                //判断图片的保存类型添加底边颜色 解决底边颜色全是透明的情况.
                cvs.fillStyle="#031D38"
                cvs.fillRect(0, 0,$('#vis_box canvas').width(),$('#vis_box canvas').height());
                cvs.drawImage(oc,0,0,$('#vis_box canvas').width(),$('#vis_box canvas').height());
                imgdata = createCanvas.toDataURL(type);
                //清除createCanvas,img缓存
                createCanvas=null;
                //将mime-type改为image/octet-stream,强制让浏览器下载
                var fixtype = function (type) {
                    type = type.toLocaleLowerCase().replace(/jpg/i, 'jpeg');
                    var r = type.match(/png|jpeg|bmp|gif/)[0];
                    return 'image/' + r;
                }
                imgdata = imgdata.replace(fixtype(type), 'image/octet-stream');
                //将图片保存到本地
                var saveFile = function (data, filename) {
                    var link = document.createElement('a');
                    link.href = data;
                    link.download = filename;
                    var event = document.createEvent('MouseEvents');
                    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                    link.dispatchEvent(event);
                }
                var filename = 'graph' + parseTime(new Date(),'{y}{m}{d}') + '.' + type;
                saveFile(imgdata, filename);
            }
            download("png");
        },
        // 全屏 退出全屏
        fullScreen() {
            this.full = !this.full;
        }
    },
}
</script>

<style lang='scss' scoped>
.homebox{
    height: 100%;
    .back {
        color: #00D3FA;
        position: absolute;
        top: 1vh;
        display: flex;
        align-items: center;
        cursor: pointer;
        img {
            width: 2vh;
            margin-right: 5px;
        }
    }
    .dia-search {
        display: flex;
        justify-content: flex-end;
        margin-bottom: 12px;
        height: 28px;
    }
    .graph-box {
        height: calc(100% - 40px);
        .tab-box {
            display: flex;
            margin-left: 5vw;
            >div {
                padding: 0.5vh 1vw;
                border: 1px solid #04538E;
                background: #031D38;
                color: #eee;
                margin-right: 0.5vw;
                border-bottom: none;
                cursor: pointer;
                border-radius: 5px 5px 0 0;
                font-size: 1.2vh;
            }
            .active {
                color: #0196BD;
                border: 1px solid #01A3CD;
                border-bottom: none;
            }
        }
        .show-box {
            position: relative;
            background: #031D38;
            border: 1px solid #04538E;
            padding:  1vh 1vw;
            border-radius: 5px;
            height: calc(100% - 5vh);
        }
        .full-screen {
            position: fixed;
            background: #031D38;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
        }
    }
    .custom-menu {
        position: absolute;
        padding: 5px 0px;
        background-color: rgba(84, 92, 100, 0.8);
        top: 100px;
        left: 100px;
        border-radius: 5px;
        z-index: 1000;
        display: none;
    }
    .custom-menu div {
        padding: 5px 0px;
        text-align: center;
    }
    .custom-menu div span{
        font-family: "微软雅黑";
        font-size: 12px;
        color: rgb(255, 255, 255);
    }
    .custom-menu div span:hover {
        cursor: pointer; 
        color: orange;
    }
    .loadPng {
        position: absolute;
        right: 3vw;
        top: 2vh;
        z-index: 9999;
        cursor: pointer;
        font-size: 1.5vw;
        color: #66B1FF;
        &:hover {
            color: #66B1FF;
        }
    }
    .screenPng {
        position: absolute;
        right: 1vw;
        top: 2vh;
        z-index: 9999;
        cursor: pointer;
        font-size: 1.5vw;
        color: #66B1FF;
        &:hover {
            color: #66B1FF;
        }
    }
    .data_box {
        position: absolute;
        bottom: 1vh;
        color: #ccc;
        z-index: 9999;
    }
    .tip {
        position: absolute;
        left: 0;
        bottom: -16px;
        font-size: 12px;
        color: #E6A23C;
    }
}
</style>
